using System;
using System.Xml;
using System.Collections.Generic;
using System.Collections;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;


namespace TankWars
{

    public class mapObject
    {
        public int type;
        public Vector2 vPosition;

        public mapObject(int t, Vector2 v)
        {
            type = t;
            vPosition = v;
        }

    }

    public class GameField
    {
        //Create a list of all the map objects.
        List<mapObject> graphicObjects = new List<mapObject>(); //All the graphical overlays in a map.
        List<mapObject> spawnPoints = new List<mapObject>();    //All the spawn points in a map.


        //Create an array of all the map textures;
        Texture2D[] aryMapTextures;

        //Used to draw blocks.
        private SpriteBatch spriteBatch;

        //Temporary picture for a block.
        //private Texture2D blockTexture;

        //Matrix that contains which spaces are collidable.
        public byte[,] field;

        //Size of the collidable blocks.
        public int blockSize;

        //Width in blocks of the entire field.
        private int width;

        //Height in block of the entire field.
        private int height;

        public GameField(Texture2D[] aryMapTextures,SpriteBatch spriteBatch)
        {
            //Initialize the spritebatch
            this.spriteBatch = spriteBatch;

            //Initialize the map textures.
            this.aryMapTextures = aryMapTextures;
        }

        public void setUpLevel(String name, int w, int h)
        {
            XmlTextReader mapReader = null;
            mapReader = new XmlTextReader(name);

            while (mapReader.Read())
            {
                if (mapReader.NodeType == XmlNodeType.Element)
                {
                    if (mapReader.LocalName.Equals("CellSize"))
                    {
                        blockSize = Int32.Parse(mapReader.ReadString());
                        //Get the width and height of the map in units of blocks.
                        width = w / blockSize + 2;
                        height = h / blockSize + 2;
                        field = new byte[width, height];
                    }
                    else if (mapReader.LocalName.Equals("MapObjects"))
                    {
                        String mapObjStr = mapReader.ReadString();
                        
                        //Object Position and objType that are collected in the parsing loop.
                        Vector2 objPos = Vector2.Zero;
                        int objType=0;

                        //Token and index used in the parsing loop.
                        String token = "";
                        int index = 0;

                        //For loop parses the mapObjStr and creates new mapObjects in memory.
                        for (int s = 0; s < mapObjStr.Length; s++)
                        {
                            if (mapObjStr[s] == ' ')
                            {
                                if (index == 0)
                                {
                                    //Index 0 represent the objType.
                                    objType = Int32.Parse(token);
                                }
                                else if (index == 1)
                                {
                                    //Index 1 is for the X coordinate.
                                    objPos.X = Int32.Parse(token);
                                }
                                else if (index == 2)
                                {
                                    //Index 2 is for the Y coordinate.
                                    objPos.Y = Int32.Parse(token);
                                }
                                
                                index++;    //Increment the index.
                                token = ""; //reset token
                            }
                            else if (mapObjStr[s] == '\n')
                            {
                                //Add a new map object to memory.
                                if (objType == 0)
                                {
                                    spawnPoints.Add(new mapObject(0,objPos));
                                }
                                else
                                    graphicObjects.Add(new mapObject(objType,objPos));

                                //Reset index and token.
                                index = 0;
                                token = "";
                            }
                            else    //Continue appending token until a delimeter is reached.
                            {   
                                token += mapObjStr[s];
                            }
                        }//For:mapObjStr
                    }//If: mapReader.LocalName.Equals("MapObjects");
                    else if (mapReader.LocalName.Equals("Grid"))
                    {
                        //Get the grid string
                        String gridString = mapReader.ReadString();

                        //X and Y are used as indexes while parsing the gridString.
                        int x = 0;
                        int y = -1;//Since the string starts with a newline, start this at -1

                        //For loop parses the gridString and sets the field matrix.
                        for (int s = 0; s < gridString.Length; s++)
                        {
                            if (gridString[s] == ' ')
                            {
                                //Space represents a new coloumn, therefore 
                                //increment the X index.
                                x++; 
                            }
                            else if (gridString[s] == '\n')
                            {
                                //Newline represents a new row, therefore increment
                                //the Y index and reset the X index.
                                x = 0;
                                y++;
                            }
                            else if (gridString[s] == ';')
                            {
                                //End of string.
                                break;
                            }
                            else//The character must be a number
                            {
                                //Character is a number, therefore set the field
                                //matrix position (x,y) to the character.
                                field[x, y] = (byte)Int32.Parse(gridString[s]+" ");
                            }
                        }//For: gridString

                    }//If: Grid
                }
            }//While: read

        }//Method:setUpLevel

        //Returns the width of the map in pixels.
        public int getMapWidth()
        {
            return blockSize * width;
        }

        //Returns the height of the map in pixels.
        public int getMapHeight()
        {
            return blockSize * height;
        }

        //Does the given x,y location contain a block?
        public int getCell(int x,int y)
        {
            //Out of bounds returns zero.
            if ((x<0)||(x>=width))
              return 0;
            if ((y<0)||(y>=height))
              return 0;

            return field[x,y];
        }

        public void drawField(Player mainPlayer, Map map)
        {
            Tank tank = mainPlayer.Tank;
            this.spriteBatch.Begin();
            foreach (mapObject obj in graphicObjects)
            {
                //The opacity the object will be drawn at.
                byte opacity = 255;
                /*
                int objTop =  (int)obj.vPosition.Y-30;
                int objLeft = (int)obj.vPosition.X-30;
                int objRight = objLeft + 150;
                int objBottom = objTop + 150;

                int tankRight = (int)tank.vPosition.X + tank.tankWidth;
                int tankBottom = (int)tank.vPosition.Y + tank.tankHeight;

                if ((objRight > tank.vPosition.X) && (objLeft < tankRight))
                if ((objBottom > tank.vPosition.Y) && (objTop < tankBottom))
                {
                    opacity = 150;
                }*/

                spriteBatch.Draw(aryMapTextures[obj.type-1], map.GetTrueScreenPosition(obj.vPosition),new Color(255,255,255,opacity));
            }
            this.spriteBatch.End();
        }

        /// <summary>
        /// This gives a spawn point on the game map.  Later this can be
        /// reworked to only give a spawn point that is clear.
        /// </summary>
        /// <returns></returns>
        public Vector2 getSpawnPoint()
        {
            //If map doesn't have spawn points specified.
            if (spawnPoints.Count == 0)
                return new Vector2(100.0f, 100.0f);

            //Set temporary variable to the first spawn point in the list.
            mapObject temp = spawnPoints[0];

            //Move the first spawn point to the end of the list.
            spawnPoints.RemoveAt(0);
            spawnPoints.Add(temp);

            //Return the first spawn point.
            return temp.vPosition;
        }

        public Vector2[] getPoints(int x, int y)
        {
            Vector2[] point = new Vector2[4];

            //TopLeft
            point[0].X = x * blockSize;
            point[0].Y = y * blockSize;

            //TopRight
            point[1].X = x * blockSize + blockSize;
            point[1].Y = y * blockSize;

            //Bottom Right
            point[2].X = x * blockSize + blockSize;
            point[2].Y = y * blockSize + blockSize;

            //Bottom Left
            point[3].X = x * blockSize;
            point[3].Y = y * blockSize + blockSize;

            return point;
        }

        
}
}
